import { message, Modal } from 'antd';

const createLoadingReducer = (status) => (state, { payload }) => {
  let { loading } = state;
  const { key } = payload;
  loading = {...loading, [key]: status};
  return {
    ...state,
    loading
  };
};
// call 添加loading
const callEffect = (sagaEffects) => {
  const { put, call } = sagaEffects;
  return function* extraCallEffect(serviceFn, ...args) {
    let result;
      const config = serviceFn.withExtra || {};
      const { key, successMsg, errorMsg } = config;
      yield put({ type: 'showLoading', payload: { key } });
      try {
        result = yield call(serviceFn, ...args);
        if(result && result.status === 200){
          successMsg && message.success(successMsg);
        }
      } catch (e) {
        errorMsg && Modal.error({ title: errorMsg });
        throw e;
      } finally {
        yield put({ type: 'hideLoading', payload: { key } });
      }
      return result;
  };
};
// 加强call，新增update
const enhanceEffects = (effects = {}) => {
  const createUpdateEffect = (sagaEffects) => {
    const { put } = sagaEffects;
    return function* updateEffect(payload) {
      yield put({ type: 'updateState', payload });
    };
  };
  return Object.keys(effects).reduce((next, key) => {
    const originEffect = effects[key];
    const isArray = Array.isArray(originEffect);
    const effectFunc = isArray ? originEffect[0] : originEffect;

    function*wrapEffect(action, sagaEffects) {
      return yield effectFunc(action, {
        ...sagaEffects,
        update: createUpdateEffect(sagaEffects),
        call: callEffect(sagaEffects)
      });
    }

    next[key] = isArray ? [wrapEffect, originEffect[1]] : wrapEffect;
    return next;
  }, {});
};
// 增强Reducers
const enhanceReducers =  (reducers) => {
  return Object.assign(reducers, {
    showLoading: createLoadingReducer(true),
    hideLoading: createLoadingReducer(false),
    updateState(state, { payload }) {
      return {
        ...state,
        ...payload
      };
    }
  });
};
// 基本modal
const createModal = (model) => {
  return Object.assign({
    state: {
      loading: {}
    },
    subscriptions: {},
    effects: {},
    reducers: {}
  }, model);
};
const extend = (properties) => {
  const model = createModal(properties);
  const { effects, namespace, reducers } = properties;
  Object.assign(model.reducers, enhanceReducers(reducers, { namespace, initialState: model.state }));
  Object.assign(model.effects, enhanceEffects(effects, namespace));
  return model;
};

export default {
  extend
};
